package org.sjsu.freedoor.service;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.sjsu.freedoor.model.Freedoor;
import org.sjsu.freedoor.model.OfferList;
import org.sjsu.freedoor.model.Service;
import org.sjsu.freedoor.model.ServiceList;
import org.sjsu.freedoor.security.Securable;
import org.sjsu.freedoor.util.Utilities;

@Path("")
public class ServicesService {
	
	@GET
	@Path("services")
	@Produces(MediaType.APPLICATION_JSON)
	public Response getServices(@QueryParam("page") String page) {
		/*
		 * RETURN:  all services currently stored in our database as JSON string
		 *          includes services originating from our node and all replicated nodes
		 * EXAMPLE: 
		 *			{"services":[ 
		 *			 {"community_url":"http://10.0.0.1", "id":"12345", "name":"gardening", "type":"services", "description":"need help gardening", "status":"buying", "timestamp": "11/11/2012 13:59"},
		 *			 {"community_url":"http://10.0.0.1", "id":"12346", "name":"painting", "type":"services", "description":"willing to paint your house", "status":"buying", "timestamp": "11/11/2012 13:59"},
		 *			 {"community_url":"http://10.0.0.2", "id":"12347", "name":"tutor needed", "type":"services", "description":"looking for a math tutor", "status":"buying", "timestamp": "11/11/2012 13:59"}"
		 *			 ]}
		 */

		Freedoor fd = Freedoor.getInstance();
		
		ServiceList services;
		
		if(page == null || page.isEmpty() || Integer.parseInt(page) == 0)
			services = fd.getServices();
		else
			services = fd.getServices(Integer.parseInt(page));
		
		//services.removeForeignServices(Freedoor.SELF_URL);
		
		String msg = services.toJsonString(true, true);
		System.out.println(msg);
		
		return Response.ok(services.toJsonObject(), MediaType.TEXT_PLAIN).build();
	}
	
	@POST
	@Path("services")
	@Produces(MediaType.TEXT_PLAIN)
	@Consumes(MediaType.APPLICATION_JSON)
	@Securable
	public Response postServices(String body) {
		/*
		 * RETURN:  comma-separated list of keys for successfully committed services
		 * EXAMPLE: AB8593EF11,4729FCC03E
		 * INPUT:   {"services":[ 
		 *			 {"community_url":"http://10.0.0.1", "id":"12345", "name":"gardening", "type":"services", "description":"need help gardening", "status":"buying", "timestamp": "11/11/2012 13:59"},
		 *			 {"community_url":"http://10.0.0.1", "id":"12346", "name":"painting", "type":"services", "description":"willing to paint your house", "status":"buying", "timestamp": "11/11/2012 13:59"},
		 *			 {"community_url":"http://10.0.0.2", "id":"12347", "name":"tutor needed", "type":"services", "description":"looking for a math tutor", "status":"buying", "timestamp": "11/11/2012 13:59"}
		 *			 ]}
		 */
		
		System.out.println(body);
		
		//return new services id
		ServiceList servicesToAdd = new ServiceList();
		String resp = "";
		
		if(servicesToAdd.loadServices(body)) {
			servicesToAdd.configureAllServicesForNewLocalInsertion(Freedoor.SELF_URL);
			Freedoor fd = Freedoor.getInstance();
			resp = fd.insertOrUpdateServices(servicesToAdd);
		}
		
		return Response.ok(resp, MediaType.TEXT_PLAIN).build();
	}
	
	@GET
	@Path("services/{id}")
	@Produces(MediaType.APPLICATION_JSON)
	public Response getServiceWithID(@PathParam("id") String id) {
		/*
		 * RETURN:  service with key (MongoDB ObjectID) or NoContent if key doesn't exist
		 * EXAMPLE: {"community_url":"http://10.0.0.1", "id":"12345", "name":"gardening", "type":"services", "description":"need help gardening", "status":"buying", "timestamp": "11/11/2012 13:59"}
		 * INPUT:   AB8593EF11
		 */
		
		System.out.println("get for id" + id);
		
		Freedoor fd = Freedoor.getInstance();
		Service service = fd.getService(id);
		if ( service == null ) {
			return Response.noContent().build();
		} else {
			//return Response.ok(service.toJsonObject(), MediaType.TEXT_PLAIN).build();
			
			//change to doc format of {"services":[...]} even though know to be one item
			ServiceList lst = new ServiceList();
			lst.add(service);
			return Response.ok(lst.toJsonObject(), MediaType.TEXT_PLAIN).build();
		}
	}
	
	@PUT
	@Path("services/{id}")
	@Produces(MediaType.TEXT_PLAIN)
	@Consumes(MediaType.APPLICATION_JSON)
	@Securable
	public Response putServiceWithID(@PathParam("id") String id, String body) {
		/*
		 * RETURN:  Boolean status of update request, or NoContent if item doesn't exist
		 * EXAMPLE: TRUE
		 * INPUT:   {"services":[ 
		 *			 {"community_url":"http://10.0.0.2", "id":"12347", "name":"tutor needed", "type":"services", "description":"looking for a math tutor", "status":"buying", "timestamp": "11/11/2012 13:59"}
		 *			 ]}
		 *          Also accept non-array single JSON object
		 */
		
		String msg = "FALSE";
		
		ServiceList serviceToPut = new ServiceList();
		
		if(serviceToPut.loadServices(body) && serviceToPut.getList().size() > 0) {
			Service s = (Service)serviceToPut.getList().toArray()[0];
			//updating local
			//TODO: these kinds of checks might need to be deeper
			if(s.getURL().isEmpty() || s.getURL().equals(Freedoor.SELF_URL)) {
				if(!s.getId().isEmpty() && !id.equals(s.getId())) //ID doesn't exist
					return Response.noContent().build();

				Freedoor fd = Freedoor.getInstance();
				msg = fd.updateService(s);
			} else { //updating remote
				//TODO: not sure if should use existing or input URL for forwarding
				//forward request to remote server
				msg = Utilities.sendPutRequest(s.getFullRestfulUri(), s.toJsonObject());

				//return response
				Response.ok("Forwarded: " + msg, MediaType.TEXT_PLAIN).build();
			}
		}

		if(msg.equals(id)) //update successful
			msg = "TRUE";
		
		return Response.ok(msg, MediaType.TEXT_PLAIN).build();
	}
	
	@DELETE
	@Path("services/{id}")
	@Produces(MediaType.TEXT_PLAIN)
	@Securable
	public Response deleteServiceWithID(@PathParam("id") String id) {
		/*
		 * RETURN:  Boolean status of update request, or NoContent if item doesn't exist
		 * EXAMPLE: TRUE
		 * INPUT:   None
		 */
		
		System.out.println("delete for id" + id);
		
		String msg = "FALSE";
		
		Freedoor fd = Freedoor.getInstance();
		Service s = fd.getService(id);
		if(s == null)
			return Response.noContent().build();
		
		if(s.getURL().isEmpty() || s.getURL().equals(Freedoor.SELF_URL)) {
			Freedoor.RequestReturnType rtn = fd.removeService(id);
			if(rtn == Freedoor.RequestReturnType.IdNotFound) {
				return Response.noContent().build();
			} else if(rtn == Freedoor.RequestReturnType.Success) {
				msg = "TRUE";
			}
			
			return Response.ok(msg, MediaType.TEXT_PLAIN).build();
		} else { //updating remote
			//TODO: not sure if should use existing or input URL for forwarding
			//forward request to remote server
			msg = Utilities.sendDeleteRequest(s.getFullRestfulUri());

			//return response
			return Response.ok("Forwarded: " + msg, MediaType.TEXT_PLAIN).build();
		}
	}
	
	@GET
	@Path("services/search")
	@Produces(MediaType.APPLICATION_JSON)
	public Response searchServices(@QueryParam("name") String name, @QueryParam("status") String status, @QueryParam("page") String page) {
		/*
		 * RETURN:  all services currently stored in our database that meet input search requirements
		 * 			Supported query parameters: name TODO: add more supported query parameters
		 *          includes services originating from our node and all replicated nodes
		 *          results limited to 10 per page
		 * EXAMPLE: 
		 *			{"services":[ 
		 *			 {"community_url":"http://10.0.0.1", "id":"12345", "name":"gardening", "type":"services", "description":"need help gardening", "status":"buying", "timestamp": "11/11/2012 13:59"},
		 *			 {"community_url":"http://10.0.0.1", "id":"12346", "name":"painting", "type":"services", "description":"willing to paint your house", "status":"buying", "timestamp": "11/11/2012 13:59"},
		 *			 {"community_url":"http://10.0.0.2", "id":"12347", "name":"tutor needed", "type":"services", "description":"looking for a math tutor", "status":"buying", "timestamp": "11/11/2012 13:59"}"
		 *			 ]}
		 */
		
		if ( name == null ) {
			name = "";
		}
		if ( status == null ) {
			status = "";
		}
		
		System.out.println("searching for name: " + name);
		System.out.println("searching for status: " + status);
		System.out.println("page:" + page);
		

		Freedoor fd = Freedoor.getInstance();
		ServiceList services = null;
		
		if ( page == null || page.isEmpty() ) {
			if ( !name.equalsIgnoreCase("") && status.equalsIgnoreCase("")) {			//	Only name is specified.
				services = fd.searchServices(name, "", 0);
			} else if ( !status.equalsIgnoreCase("") && name.equalsIgnoreCase("") ) {	//	Only status is specified.
				if ( status.equalsIgnoreCase("buying") 	|| 
					 status.equalsIgnoreCase("buy") 	||	
					 status.equalsIgnoreCase("selling") ||
					 status.equalsIgnoreCase("sell") ) {
					services = fd.searchServices("", status, 0);
				}
			} else if ( !name.equalsIgnoreCase("") && !status.equalsIgnoreCase("") ) {	//	both name and status are specified.
				services = fd.searchServices(name, status, 0);
			} else if ( name.equalsIgnoreCase("") && status.equalsIgnoreCase("") ) {	//	none of name and status is specified.)
				services = fd.searchServices("", "", 0);
			}
		}		
		else {
			if ( !name.equalsIgnoreCase("") && status.equalsIgnoreCase("")) {			//	Only name is specified.
				services = fd.searchServices(name, "", Integer.parseInt(page));
			} else if ( !status.equalsIgnoreCase("") && name.equalsIgnoreCase("") ) {	//	Only status is specified.
				if ( status.equalsIgnoreCase("buying") 	|| 
					 status.equalsIgnoreCase("buy") 	||	
					 status.equalsIgnoreCase("selling") ||
					 status.equalsIgnoreCase("sell") ) {
					services = fd.searchServices("", status, Integer.parseInt(page));
				}
			} else if ( !name.equalsIgnoreCase("") && !status.equalsIgnoreCase("") ) {	//	both name and status are specified.
				services = fd.searchServices(name, status, Integer.parseInt(page));
			} else if ( name.equalsIgnoreCase("") && status.equalsIgnoreCase("") ) {	//	none of name and status is specified.)
				services = fd.searchServices("", "", Integer.parseInt(page));
			}
			
			
		}
		
		String msg = "";
		if (services != null) {
			//services.removeForeignServices(Freedoor.SELF_URL);
			msg = services.toJsonString(true, true);
			System.out.println(msg);
			return Response.ok(services.toJsonObject(), MediaType.TEXT_PLAIN).build();
		}
		
		return Response.noContent().build();
	}
	
	@GET
	@Path("services/{id}/offers")
	@Produces(MediaType.APPLICATION_JSON)
	@Securable
	public Response getOffersForServiceID(@PathParam("id") String oid) {
		/*
		 * RETURN:  all offers for input service, or NoContent if service doesn't exist
		 * EXAMPLE: 
		 *			{"offers":[ 
		 *			 {"message":"i want to buy your services" , "email":"john@doe.com", "id":" http://anothernode/services/12345"},"
		 *           {"message":"i want to buy your services too" , "email":"jane@doe.com", "id":" http://anothernode/services/12345"}"
		 *			 ]}
		 */
		System.out.println("get offers for id " + oid);
				
		Freedoor fd = Freedoor.getInstance();
		
		OfferList offers  = fd.getOffersForService(oid);
		
		if(offers == null && fd.getService(oid) == null)
			return Response.noContent().build();
		
		String msg = offers.toJsonString(true, true);
		System.out.println(msg);
		
		return Response.ok(offers.toJsonObject(), MediaType.TEXT_PLAIN).build();
	}

	@POST
	@Path("services/{id}/offers")
	@Produces(MediaType.TEXT_PLAIN)
	@Consumes(MediaType.APPLICATION_JSON)
	public Response postOffersForServiceID(@PathParam("id") String oid, String body) {
		/*
		 * RETURN:  Boolean status or NoContent if service doens't exist
		 * EXAMPLE: AB8593EF11,4729FCC03E
		 * INPUT:   {"offers":[{"email":"fake@fake.com", "message":"I'd like to meet Tom Sawyer in exchange", "id":""}]}
		 */
		
		System.out.println("posting offer for id: " + oid);
		System.out.println(body);
		String msg = "FALSE";

		//TODO: for efficiency, see if service exists first
		OfferList offers = new OfferList();
		if(offers.loadOffers(body)) {
			Freedoor fd = Freedoor.getInstance();
			
			Service serviceToAddTo = fd.getService(oid);

			if(serviceToAddTo == null)
				return Response.noContent().build();

			if(serviceToAddTo.getURL().isEmpty() || serviceToAddTo.getURL().equals(Freedoor.SELF_URL)) {
				msg = fd.putOffersForService(oid, offers);
			} else {
				//forward request to remote server
				msg = Utilities.sendPutRequest(serviceToAddTo.getURL(), serviceToAddTo.toJsonObject());

				//return response
				return Response.ok("Forwarded: " + msg, MediaType.TEXT_PLAIN).build();
			}
		}
		
		return Response.ok(msg, MediaType.TEXT_PLAIN).build();
	}

}
